//
//  XPPXcodePlugin.m
//  XPPXcodePlugin
//
//  Created by yoyokko on 10-4-18.
//  Copyright 2010 yoyokko@gmail.com. All rights reserved.
//

#import "XPPXcodePlugin.h"
#import "PBXPreferencesModule.h"
#import "XPPXcodeMenuItem.h"
#import "XPPXcodePreferences.h"
#import "XPPXcodeRegisterMenuItem.h"
#import "GTMObjC2Runtime.h"
#import "XPPAutoCompleteHelper.h"

BOOL swizzleMethods(Class ourClass, Class originalClass, SEL ourSelector, SEL originalSeletor)
{
	Method ourMethod = class_getInstanceMethod(ourClass, ourSelector);
	if (class_addMethod(originalClass,
						ourSelector,
						method_getImplementation(ourMethod),
						method_getTypeEncoding(ourMethod))) {
		ourMethod = class_getInstanceMethod(originalClass, ourSelector);
		Method theirMethod
		= class_getInstanceMethod(originalClass, originalSeletor);
		method_exchangeImplementations(ourMethod, theirMethod);
		return YES;
	}
	return NO;
}

@interface XPPXcodePlugin (PrivateMethods)

// Called when the preference panel has been loaded so we can set up our
// preference pane.
- (void)preferencesPanelDidLoadNotification:(NSNotification *)notification;

// Called whenever a menu item is added to the list
- (void)addedMenuItem:(NSNotification *)notification;

// Called whenever the pref for showing the menuitem icon changes
- (void)updateMenuIcons:(NSNotification *)notification;

// the image to use for our menu items
- (NSImage *)imageForMenuItems;
@end

// Our dictionary of menu items to add
static NSMutableDictionary *gRegisteredMenuItems = nil;

static NSMutableArray *gRegisteredClasses = nil;

@implementation XPPXcodePlugin

+ (void) load
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	if (![XPPXcodeRegisterMenuItem isRegistered])
	{
		NSRunAlertPanel(@"Infomation",
						@"You're runing a copy of unregistered XPP Xcode Plugin.\nYou can pay for more features with Register menu in Xcode's main menu'.",
						@"OK", @"", @"");
	}
	[pool release];
	
}

+ (void)registerMenuItem:(id)item {
	@synchronized([self class]) {
		static int gTag = 0xEAFE;
		if (!gRegisteredMenuItems) {
			gRegisteredMenuItems = [[NSMutableDictionary alloc] init];
		}
		if (item) {
			[gRegisteredMenuItems setObject:item
									 forKey:[NSNumber numberWithInt:gTag++]];
		}
	}
}

+ (void)registerSwizzleClass:(Class)cls {
	@synchronized([self class]) {
		if (!gRegisteredClasses) {
			gRegisteredClasses = [[NSMutableArray alloc] init];
		}
		if (cls) {
			[gRegisteredClasses addObject:cls];
		}
	}
}

- (id)init {
	self = [super init];
	if (!self) return nil;
	
	NSBundle *bundle = [NSBundle bundleForClass:[self class]];
	NSString *version = [bundle objectForInfoDictionaryKey:@"CFBundleVersion"];
	NSLog(@"XPPXcodePlugin loaded (%@)", version);
	[XPPAutoCompleteHelper sharedXPPAutoCompleteHelper];
	
	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
	
	[nc addObserver:self
		   selector:@selector(preferencesPanelDidLoadNotification:)
			   name:PBXPreferencesPanelDidLoadNotification
			 object:nil];
	
	[nc addObserver:self
		   selector:@selector(addedMenuItem:)
			   name:NSMenuDidAddItemNotification
			 object:[NSApp mainMenu]];
	
	[nc addObserver:self
		   selector:@selector(updateMenuIcons:)
			   name:XPPXcodePreferencesMenuItemPrefChanged
			 object:nil];
	
	NSEnumerator *enumerator = [gRegisteredClasses objectEnumerator];
	Class cls;
	while ((cls = [enumerator nextObject])) {
		[[[cls alloc] init] autorelease];
	}
	return self;
}

- (void)dealloc {
	[[NSNotificationCenter defaultCenter] removeObserver:self];
	[gRegisteredMenuItems removeAllObjects];
	[gRegisteredMenuItems release];
	[gRegisteredClasses removeAllObjects];
	[gRegisteredClasses release];
	
	[super dealloc];
}


- (void)preferencesPanelDidLoadNotification:(NSNotification *)notification {
	XPPXcodePreferences *prefs = [[[XPPXcodePreferences alloc] init] autorelease];
	[[PBXPreferencesModule sharedPreferences] addPreferenceNamed:@"Xcode++"
														   owner:prefs];
}

- (NSImage *)imageForMenuItems {
	NSBundle *pluginBundle = [XPPXcodePlugin pluginBundle];
	NSString *path = [pluginBundle pathForResource:@"XPP"
											ofType:@"icns"];
	NSImage *image = [[[NSImage alloc] initWithContentsOfFile:path] autorelease];
	[image setScalesWhenResized:YES];
	[image setSize:NSMakeSize(16, 16)];
	return image;
}

- (void)addedMenuItem:(NSNotification *)notification {
	NSMenu *menu = [notification object];
	NSNumber *idx = [[notification userInfo] objectForKey:@"NSMenuItemIndex"];
	NSMenuItem *menuItem = [menu itemAtIndex:[idx intValue]];
	if ([[menuItem title] isEqualToString:@"User Scripts"]) {
		NSImage *image = nil;
		if ([XPPXcodePreferences showImageOnMenuItems]) {
			image = [self imageForMenuItems];
		}
		NSArray *sortedKeys
		= [gRegisteredMenuItems keysSortedByValueUsingSelector:@selector(compareDepth:)];
		NSEnumerator *keyEnum = [sortedKeys objectEnumerator];
		NSNumber *key;
		while ((key = [keyEnum nextObject])) {
			id<XPPXcodeMenuItemProtocol> item = [gRegisteredMenuItems objectForKey:key];
			NSInteger insertionIndex = [item insertionIndex];
			NSMenu *insertionMenu = [item insertionMenu];
			NSInteger itemCount = [insertionMenu numberOfItems];
			if (insertionIndex > itemCount) {
				insertionIndex = itemCount;
			}
			NSString *itemTitle = [item title];
			if ([itemTitle isEqualToString:@"-"]) {
				[insertionMenu insertItem:[NSMenuItem separatorItem]
								  atIndex:insertionIndex];
			} else {
				menuItem = [insertionMenu insertItemWithTitle:[item title]
													   action:[item actionSelector]
												keyEquivalent:[item keyEquivalent]
													  atIndex:insertionIndex];
				if (image && [item allowXPPMenuIcon]) {
					[menuItem setImage:image];
				}
				[menuItem setTarget:item];
				[menuItem setTag:[key intValue]];
				[item wasInserted:menuItem];
			}
		}
	}
}

- (void)updateMenuIcons:(NSNotification *)notification {
	// we use our own notification since the normal defaults one doesn't let you
	// tell which changed.
	NSImage *image = nil;
	if ([XPPXcodePreferences showImageOnMenuItems]) {
		image = [self imageForMenuItems];
	}
	NSEnumerator *keyEnum = [gRegisteredMenuItems keyEnumerator];
	NSNumber *key;
	while ((key = [keyEnum nextObject])) {
		id<XPPXcodeMenuItemProtocol> item = [gRegisteredMenuItems objectForKey:key];
		NSMenu *insertionMenu = [item insertionMenu];
		NSMenuItem *menuItem = [insertionMenu itemWithTag:[key intValue]];
		// play it safe, make sure it's the right target
		if (menuItem && (item == [menuItem target])) {
			// if the user wants images and this item should get it, then set the
			// image.  if either wasn't true, just set it to nil to clear the
			// menu.
			if (image && [item allowXPPMenuIcon]) {
				[menuItem setImage:image];
			} else {
				[menuItem setImage:nil];
			}
		}
	}
}

+ (NSBundle*)pluginBundle {
	return [NSBundle bundleForClass:self];
}

+ (float)xCodeVersion {
	NSBundle *bundle = [NSBundle mainBundle];
	id object = [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
	float value = [object floatValue];
	if (!(value > 0.0)) {
		NSLog(@"Unable to get Xcode Version");
	}
	return value;
}

@end
